#!/usr/bin/env python3
"""
人类行为模拟器 - 第一阶段增强
负责模拟真实用户的浏览行为，对抗行为检测
"""

import logging
import random
import time
import asyncio
import math
from typing import Dict, List, Optional, Tuple, Any
from playwright.sync_api import Page

logger = logging.getLogger(__name__)

class BehaviorSimulator:
    """人类行为模拟器 - 增强版"""
    
    def __init__(self):
        self.behavior_patterns = self.load_behavior_patterns()
        self.current_session_data = {
            'pages_visited': 0,
            'total_time_spent': 0,
            'last_interaction_time': 0
        }
    
    def load_behavior_patterns(self) -> Dict[str, Any]:
        """加载行为模式配置"""
        return {
            'reading_speeds': {
                'fast': 300,      # 字符/分钟
                'normal': 200,    # 字符/分钟
                'slow': 120       # 字符/分钟
            },
            'scroll_patterns': {
                'smooth': {'steps': 10, 'delay_range': (0.1, 0.3)},
                'step_by_step': {'steps': 5, 'delay_range': (0.5, 1.0)},
                'quick_scan': {'steps': 3, 'delay_range': (0.2, 0.5)}
            },
            'mouse_patterns': {
                'active': {'movements_per_minute': 15, 'click_probability': 0.1},
                'normal': {'movements_per_minute': 8, 'click_probability': 0.05},
                'passive': {'movements_per_minute': 3, 'click_probability': 0.02}
            }
        }
    
    def calculate_reading_time(self, page: Page) -> float:
        """基于页面内容计算真实阅读时间"""
        try:
            # 获取页面文本内容长度
            content_length = page.evaluate("""
                () => {
                    const text = document.body.innerText || '';
                    return text.length;
                }
            """)
            
            # 选择阅读速度（正态分布）
            speed_type = random.choices(
                ['fast', 'normal', 'slow'],
                weights=[0.2, 0.6, 0.2]
            )[0]
            
            base_speed = self.behavior_patterns['reading_speeds'][speed_type]
            
            # 添加随机变化（±30%）
            actual_speed = base_speed * random.uniform(0.7, 1.3)
            
            # 计算阅读时间（秒）
            reading_time = (content_length / actual_speed) * 60
            
            # 设置合理的时间范围（10秒到5分钟）
            reading_time = max(10, min(300, reading_time))
            
            logger.debug(f"[BEHAVIOR] 内容长度: {content_length}, 阅读时间: {reading_time:.1f}秒")
            return reading_time
            
        except Exception as e:
            logger.warning(f"[BEHAVIOR] 计算阅读时间失败: {e}")
            return random.uniform(15, 45)  # 默认15-45秒
    
    def generate_mouse_trajectory(self, start: Tuple[int, int], end: Tuple[int, int]) -> List[Tuple[int, int]]:
        """生成自然的鼠标移动轨迹（贝塞尔曲线）"""
        x1, y1 = start
        x4, y4 = end
        
        # 生成控制点
        x2 = x1 + random.randint(-100, 100)
        y2 = y1 + random.randint(-50, 50)
        x3 = x4 + random.randint(-100, 100)
        y3 = y4 + random.randint(-50, 50)
        
        # 贝塞尔曲线点数
        num_points = random.randint(15, 25)
        trajectory = []
        
        for i in range(num_points):
            t = i / (num_points - 1)
            
            # 三次贝塞尔曲线公式
            x = int((1-t)**3 * x1 + 3*(1-t)**2*t * x2 + 3*(1-t)*t**2 * x3 + t**3 * x4)
            y = int((1-t)**3 * y1 + 3*(1-t)**2*t * y2 + 3*(1-t)*t**2 * y3 + t**3 * y4)
            
            trajectory.append((x, y))
        
        return trajectory
    
    def simulate_natural_mouse_movement(self, page: Page, duration: float):
        """模拟自然的鼠标移动"""
        try:
            pattern_type = random.choice(['active', 'normal', 'passive'])
            pattern = self.behavior_patterns['mouse_patterns'][pattern_type]
            
            movements_count = int((duration / 60) * pattern['movements_per_minute'])
            movements_count = max(1, movements_count)  # 至少移动一次
            
            viewport = page.viewport_size
            if not viewport:
                viewport = {'width': 1920, 'height': 1080}
            
            current_pos = (
                random.randint(100, viewport['width'] - 100),
                random.randint(100, viewport['height'] - 100)
            )
            
            for i in range(movements_count):
                # 生成目标位置
                target_pos = (
                    random.randint(100, viewport['width'] - 100),
                    random.randint(100, viewport['height'] - 100)
                )
                
                # 生成轨迹
                trajectory = self.generate_mouse_trajectory(current_pos, target_pos)
                
                # 执行移动
                for x, y in trajectory:
                    page.mouse.move(x, y)
                    time.sleep(random.uniform(0.01, 0.03))
                
                current_pos = target_pos
                
                # 随机点击
                if random.random() < pattern['click_probability']:
                    page.mouse.click(current_pos[0], current_pos[1])
                    time.sleep(random.uniform(0.1, 0.3))
                
                # 移动间隔
                if i < movements_count - 1:
                    time.sleep(random.uniform(2, 8))
                    
        except Exception as e:
            logger.warning(f"[BEHAVIOR] 鼠标移动模拟失败: {e}")
    
    def simulate_natural_scrolling(self, page: Page, duration: float):
        """模拟自然的滚动行为"""
        try:
            pattern_type = random.choice(['smooth', 'step_by_step', 'quick_scan'])
            pattern = self.behavior_patterns['scroll_patterns'][pattern_type]
            
            # 获取页面高度
            page_height = page.evaluate("() => document.body.scrollHeight")
            viewport_height = page.evaluate("() => window.innerHeight")
            
            if page_height <= viewport_height:
                return  # 页面太短，无需滚动
            
            scroll_distance = page_height - viewport_height
            step_size = scroll_distance / pattern['steps']
            
            current_position = 0
            
            for i in range(pattern['steps']):
                # 计算滚动位置（添加随机变化）
                target_position = current_position + step_size * random.uniform(0.8, 1.2)
                target_position = min(target_position, scroll_distance)
                
                # 执行滚动
                page.evaluate(f"window.scrollTo(0, {target_position})")
                current_position = target_position
                
                # 滚动后停留
                delay = random.uniform(*pattern['delay_range'])
                time.sleep(delay)
                
                # 偶尔向上滚动一点（模拟重新阅读）
                if random.random() < 0.2 and i > 0:
                    back_scroll = random.uniform(50, 200)
                    page.evaluate(f"window.scrollTo(0, {max(0, current_position - back_scroll)})")
                    time.sleep(random.uniform(1, 3))
                    page.evaluate(f"window.scrollTo(0, {current_position})")
            
            # 最后滚动到底部
            page.evaluate(f"window.scrollTo(0, {scroll_distance})")
            
        except Exception as e:
            logger.warning(f"[BEHAVIOR] 滚动模拟失败: {e}")
    
    def simulate_page_interaction(self, page: Page):
        """模拟页面交互行为"""
        try:
            # 随机选择交互类型
            interactions = ['hover_elements', 'focus_inputs', 'click_links']
            interaction_type = random.choice(interactions)
            
            if interaction_type == 'hover_elements':
                # 悬停在一些元素上
                elements = page.query_selector_all('a, button, .shop-item, .title')
                if elements:
                    selected_elements = random.sample(elements, min(3, len(elements)))
                    for element in selected_elements:
                        try:
                            element.hover()
                            time.sleep(random.uniform(0.5, 2.0))
                        except:
                            continue
            
            elif interaction_type == 'focus_inputs':
                # 聚焦输入框
                inputs = page.query_selector_all('input, textarea')
                if inputs:
                    selected_input = random.choice(inputs)
                    try:
                        selected_input.focus()
                        time.sleep(random.uniform(1, 3))
                    except:
                        pass
            
            elif interaction_type == 'click_links':
                # 点击一些链接（但不跳转）
                links = page.query_selector_all('a[href^="#"], .tab-item')
                if links:
                    selected_link = random.choice(links)
                    try:
                        selected_link.click()
                        time.sleep(random.uniform(1, 2))
                    except:
                        pass
                        
        except Exception as e:
            logger.warning(f"[BEHAVIOR] 页面交互模拟失败: {e}")
    
    def simulate_realistic_browsing(self, page: Page) -> float:
        """模拟完整的真实浏览行为"""
        logger.info("[BEHAVIOR] 开始模拟真实用户浏览行为")
        
        start_time = time.time()
        
        try:
            # 1. 等待页面完全加载
            page.wait_for_load_state('networkidle', timeout=10000)
            time.sleep(random.uniform(1, 3))  # 模拟用户反应时间
            
            # 2. 计算阅读时间
            reading_time = self.calculate_reading_time(page)
            
            # 3. 并行执行多种行为
            total_behavior_time = reading_time * random.uniform(0.8, 1.2)
            
            # 分配时间给不同行为
            mouse_time = total_behavior_time * 0.6
            scroll_time = total_behavior_time * 0.3
            interaction_time = total_behavior_time * 0.1
            
            # 4. 执行鼠标移动（后台进行）
            import threading
            mouse_thread = threading.Thread(
                target=self.simulate_natural_mouse_movement,
                args=(page, mouse_time)
            )
            mouse_thread.start()
            
            # 5. 执行滚动行为
            time.sleep(random.uniform(2, 5))  # 初始停留
            self.simulate_natural_scrolling(page, scroll_time)
            
            # 6. 执行页面交互
            if random.random() < 0.4:  # 40%概率进行交互
                self.simulate_page_interaction(page)
            
            # 7. 等待鼠标移动完成
            mouse_thread.join()
            
            # 8. 最终停留
            final_stay = random.uniform(3, 8)
            time.sleep(final_stay)
            
            actual_time = time.time() - start_time
            logger.info(f"[BEHAVIOR] 用户行为模拟完成，耗时: {actual_time:.1f}秒")
            
            # 更新会话数据
            self.current_session_data['pages_visited'] += 1
            self.current_session_data['total_time_spent'] += actual_time
            self.current_session_data['last_interaction_time'] = time.time()
            
            return actual_time
            
        except Exception as e:
            logger.error(f"[BEHAVIOR] 行为模拟异常: {e}")
            # 失败时至少等待一段时间
            time.sleep(random.uniform(10, 20))
            return time.time() - start_time
    
    def get_session_stats(self) -> Dict[str, Any]:
        """获取当前会话统计信息"""
        return self.current_session_data.copy()
    
    def reset_session(self):
        """重置会话数据"""
        self.current_session_data = {
            'pages_visited': 0,
            'total_time_spent': 0,
            'last_interaction_time': 0
        }
